/*
  Copyright 1991 Scott Hess.  Permission to use, copy, modify, and
  distribute this software and its documentation for any purpose
  and without fee is hereby granted, provided that this copyright
  notice appear in all copies.  The copyright notice need not appear
  on binary-only distributions - just in source code.
  
  Scott Hess makes no representations about the suitability of this
  software for any purpose.  It is provided "as is" without express
  or implied warranty.
*/

/* Generated by Interface Builder */

/******************************************************************************************************************************
 *    As its name implies, this object is the application delegate.  It handles setting up the program and cleaning up        *
 *    when the program terminates.                                                                                            *
 ******************************************************************************************************************************/

//#import <mach.h>
#import <mach/mach.h>		/* for 3.0 compatibility -- drue */
#import <stdlib.h>
//#import <defaults.h>
#import <defaults/defaults.h>	/* for 3.0 compatibility -- drue */
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/NXImage.h>
#import "AppDelegate.h"
#import "Monitor.h"

#define MINPOLLINTERVAL 0.1
#define MINFLIPINTERVAL 0.1

float pollInterval = 1.0;

@implementation AppDelegate

- appWillInit:sender
{
struct task_basic_info 	tbi;
unsigned int 		ic = TASK_BASIC_INFO_COUNT;

    if( task_info(task_self(),TASK_BASIC_INFO,(task_info_t)&tbi,&ic) != KERN_SUCCESS )
        return nil;
    task_priority(task_self(),tbi.base_priority-4,TRUE);

    return self;
}

- appDidInit:sender
{
Window	*iconWindow;
id 	iconView;
NXImage *recessed;
NXRect	monitorRect;
NXDefaultsVector defs =
    {
    {"PollInterval","1.0"},
    {"FlipInterval","0.0"},
    {"DisplayInfo", "CDMN"},
    {"InfoType","0"},
    {NULL,NULL}
    };

    /**************************************************************************************************************************
     *    Instantiate the NXImages needed to do the drawing                                                                   *
     **************************************************************************************************************************/
    recessed = [NXImage findImageNamed:"recessed.tiff"];

    /**************************************************************************************************************************
     *    Get the application icon's view and put our own views there.                                                        *
     **************************************************************************************************************************/
    iconWindow = [NXApp appIcon];
    iconView = [iconWindow contentView];
    [iconView addSubview:monitor];
    [iconView lockFocus];
    [monitor getFrame:&monitorRect];
    [recessed composite:NX_COPY toPoint:&(monitorRect.origin)];
    [iconView unlockFocus];

    [iconWindow flushWindow];

    [recessed free];

    /**************************************************************************************************************************
     *    Register the defaults with the system.                                                                              *
     **************************************************************************************************************************/
    NXRegisterDefaults([NXApp appName],defs);
    if ( NXGetDefaultValue([NXApp appName],"PollInterval") )
        {
        pollInterval = atof(NXGetDefaultValue([NXApp appName],"PollInterval"));
        pollInterval = MAX(pollInterval,MINPOLLINTERVAL);
	[pollSlider setFloatValue:pollInterval];
        [pollText setFloatValue:pollInterval];
        }
	
    if ( NXGetDefaultValue([NXApp appName],"FlipInterval") )
        {
        flipInterval = atof(NXGetDefaultValue([NXApp appName],"FlipInterval"));
        if ( flipInterval > MINFLIPINTERVAL )
	    {
	    [flipSlider setFloatValue:flipInterval];
            [flipText setFloatValue:flipInterval];
	    }
        else
            {
	    [flipSlider setFloatValue:0.0];
	    [flipText setStringValue:"OFF"];
	    }
        }
	
    displayCpu = displayDisk = displayMemory = displayNetwork = TRUE;
    if ( NXGetDefaultValue([NXApp appName],"DisplayInfo") )
        {
	strcpy( displayInfo, NXGetDefaultValue([NXApp appName],"DisplayInfo"));
	  //  a lowercase value means the matching option is turned off
	if ( strchr(displayInfo, 'c') ) displayCpu = FALSE;
	if ( strchr(displayInfo, 'd') ) displayDisk = FALSE;
	if ( strchr(displayInfo, 'm') ) displayMemory = FALSE;
	if ( strchr(displayInfo, 'n') ) displayNetwork = FALSE;
        }
    if ( (displayCpu + displayDisk + displayMemory + displayNetwork) < 1) displayCpu = TRUE;
    if ( displayCpu ) [cpuSwitch setState:1];
    if ( displayDisk ) [diskSwitch setState:1];
    if ( displayMemory ) [memorySwitch setState:1];
    if ( displayNetwork ) [networkSwitch setState:1];
	
    if ( NXGetDefaultValue([NXApp appName],"InfoType") )
        {
        tag = atoi(NXGetDefaultValue([NXApp appName],"InfoType"));
        switch ( tag )
            {
            case CPU:
                break;
            case MEMORY:
                break;
            case DISK:
                break;
            case NETWORK:
                break;
            default:
                tag = CPU;
	            }
        }
    [monitor flip:self];

    /**************************************************************************************************************************
     *    Register the timed entry with the window server.                                                                    *
     **************************************************************************************************************************/
    stepEntry = DPSAddTimedEntry(pollInterval,(void *)_step,monitor,NX_MODALRESPTHRESHOLD);
    if ( flipInterval > MINFLIPINTERVAL )
        flipEntry = DPSAddTimedEntry(flipInterval*60,(void *)_flip,self,NX_MODALRESPTHRESHOLD);
    return self;	
}

- appWillTerminate:sender
{
    if ( stepEntry )
        {
        DPSRemoveTimedEntry(stepEntry);
        stepEntry = (DPSTimedEntry)0;
        }
    if ( flipEntry )
        {
        DPSRemoveTimedEntry(flipEntry);
        flipEntry = (DPSTimedEntry)0;
        }
    return self;
}

- info:sender
{
    if ( !infoPanel )
        [NXApp loadNibSection:"InfoPanel.nib" owner:self];
    [infoPanel makeKeyAndOrderFront:self];
    return self;
}

- flipMonitor
{
    tag++;
    if ( tag > TYPE_MAX )
        tag = 0;

    //  ordering of the following checks is important (they work based on the
    //  specific values and order-in-values of the tags in question).
    if ( tag == CPU && ! displayCpu ) tag++;		// checking tag == 0
    if ( tag == DISK && ! displayDisk) tag++;		// checking tag == 1
    if ( tag == MEMORY && ! displayMemory ) tag++;	// checking tag == 2
    if ( tag == NETWORK && ! displayNetwork) tag++;	// checking tag == 3
    if ( tag > TYPE_MAX )
        tag = 0;
    [monitor flip:self];
    return self;
}

- setPollInterval:sender
{
char intervalString[6];

    pollInterval = MAX([sender floatValue],MINPOLLINTERVAL);
    sprintf(intervalString,"%4.1f",pollInterval);
    NXWriteDefault([NXApp appName],"PollInterval",intervalString);
    if ( stepEntry )
        {
        DPSRemoveTimedEntry(stepEntry);
        stepEntry = (DPSTimedEntry)0;
        }
    stepEntry = DPSAddTimedEntry(pollInterval,(void *)_step,monitor,NX_MODALRESPTHRESHOLD);
    [pollText setStringValue:intervalString];
    return self;
}

- setFlipInterval:sender
{
char intervalString[6];

    flipInterval = [sender floatValue];
    if ( flipEntry )
        {
        DPSRemoveTimedEntry(flipEntry);
        flipEntry = (DPSTimedEntry)0;
        }
    if ( flipInterval > MINFLIPINTERVAL )
        {
        sprintf(intervalString,"%4.1f",flipInterval);
        flipEntry = DPSAddTimedEntry(flipInterval*60,(void *)_flip,self,NX_MODALRESPTHRESHOLD);
        }
    else
        strcpy(intervalString,"OFF");
    [flipText setStringValue:intervalString];
    NXWriteDefault([NXApp appName],"FlipInterval",intervalString);
    return self;
}

- setDisplayCpu:sender
{
    displayCpu = [cpuSwitch state];
    [self saveDisplayInfo];
    if ( displayCpu ) { tag = CPU ; [monitor flip:self]; }
    else if ( tag == CPU ) { [self flipMonitor]; }
    return self;
}

- setDisplayDisk:sender
{
    displayDisk = [diskSwitch state];
    [self saveDisplayInfo];
    if ( displayDisk ) { tag = DISK ; [monitor flip:self]; }
    else if ( tag == DISK ) { [self flipMonitor]; }
    return self;
}

- setDisplayMemory:sender
{
    displayMemory = [memorySwitch state];
    [self saveDisplayInfo];
    if ( displayMemory ) { tag = MEMORY ; [monitor flip:self]; }
    else if ( tag == MEMORY ) { [self flipMonitor]; }
    return self;
}

- setDisplayNetwork:sender
{
    displayNetwork = [networkSwitch state];
    [self saveDisplayInfo];
    if ( displayNetwork ) { tag = NETWORK ; [monitor flip:self]; }
    else if ( tag == NETWORK ) { [self flipMonitor]; }
    return self;
}

- saveDisplayInfo
{
    //    at least one option must be on...
    if ( (displayCpu + displayDisk + displayMemory + displayNetwork) < 1) 
	{
	displayCpu = TRUE;		// Note that this always works, while
	[cpuSwitch setState:1];		// This only works if called from setDisplayCpu?!?
	}

    displayInfo[0] = '\0';
    if ( displayCpu )	strcat(displayInfo, "C");
    else		strcat(displayInfo, "c");
    if ( displayDisk )	strcat(displayInfo, "D");
    else		strcat(displayInfo, "d");
    if ( displayMemory ) strcat(displayInfo, "M");
    else		strcat(displayInfo, "m");
    if ( displayNetwork ) strcat(displayInfo, "N");
    else		strcat(displayInfo, "n");

    NXWriteDefault([NXApp appName], "DisplayInfo", displayInfo);
    return self;
}

- selectedCell
{
    return self;
}

- (int)tag
{
    return tag;
}

@end

/******************************************************************************************************************************
 *    This function is called by a timed entry.                                                                               *
 *    It gets the load data from the system.                                                                                  *
 ******************************************************************************************************************************/
void _step(DPSTimedEntry teNumber,double now,id monitor)
{
    [monitor step];
    return;
}

void _flip(DPSTimedEntry teNumber,double now,id self)
{
    [self flipMonitor];
    return;
}




